/*
 * Copyright (c) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { Authenticator } from './Authenticator'
import { Credentials } from './Credentials'
import { Request } from './Request'
import { Response } from './Response'
import { Route } from './Route'

/**
 * 代理认证器
 *
 * 为 HTTP 代理提供 Basic 认证支持。
 * 与原版 OkHttp 设计一致，认证信息独立于 Proxy 对象。
 *
 * 使用示例：
 * ```typescript
 * const proxy = Proxy.createHttpProxy('proxy.example.com', 8080)
 *
 * const client = new OkHttpClient.Builder()
 *   .proxy(proxy)
 *   .proxyAuthenticator(ProxyAuthenticator.basic('user', 'pass'))
 *   .build()
 * ```
 */
export class ProxyAuthenticator implements Authenticator {
  private username: string
  private password: string

  private constructor(username: string, password: string) {
    this.username = username
    this.password = password
  }

  /**
   * 实现认证接口
   * 当收到 407 Proxy Authentication Required 响应时被调用
   */
  authenticate(route: Route, response: Response): Request | null {
    // 如果已经尝试过认证，避免无限循环
    if (response.request.header('Proxy-Authorization') !== null) {
      console.warn('[ProxyAuthenticator] Already attempted authentication, giving up')
      return null
    }

    // 生成 Basic 认证凭证
    const credential = Credentials.basic(this.username, this.password)

    // 返回带有 Proxy-Authorization 头的新请求
    return response.request.newBuilder()
      .header('Proxy-Authorization', credential)
      .build()
  }


  /**
   * 使用指定的用户名和密码创建 Basic 认证器
   *
   * @param username 用户名
   * @param password 密码
   * @returns 代理认证器
   */
  static basic(username: string, password: string): ProxyAuthenticator {
    return new ProxyAuthenticator(username, password)
  }
}

/**
 * 预先认证的代理认证器
 *
 * 在发送请求前就添加 Proxy-Authorization 头，而不是等待 407 响应。
 * 这在某些代理服务器上可以减少一次往返。
 */
export class PreemptiveProxyAuthenticator implements Authenticator {
  private username: string
  private password: string

  constructor(username: string, password: string) {
    this.username = username
    this.password = password
  }

  authenticate(route: Route, response: Response): Request | null {
    // 检查是否是预先认证请求 (OkHttp-Preemptive challenge)
    const challenges = response.challenges()
    for (const challenge of challenges) {
      if (challenge.scheme.toLowerCase() === 'okhttp-preemptive') {
        const credential = Credentials.basic(this.username, this.password)
        return response.request.newBuilder()
          .header('Proxy-Authorization', credential)
          .build()
      }
    }

    // 如果已经尝试过认证，避免无限循环
    if (response.request.header('Proxy-Authorization') !== null) {
      return null
    }

    // 响应式认证
    const credential = Credentials.basic(this.username, this.password)
    return response.request.newBuilder()
      .header('Proxy-Authorization', credential)
      .build()
  }

}


